﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Base;

namespace ConsoleApp.Test
{
    internal class TestSecurity
    {
        public static void Test()
        {
            //var rsr1 = new RSACng();
            //var rsr2 = new RSAOpenSsl();
            var rsr3 = RSA.Create();// new RSACryptoServiceProvider();
            var rsr4 = new RSACryptoServiceProvider();

            //TestGetAlgorithmType();
            //TestComputeHash();
            TestSymmetric();
            TestRSR();
        }

        private static void TestRSR()
        {
            //数据长度与密钥长度关系,117-1024, 214-2048
            byte[] data = new byte[214];
            byte value = 0;
            for (int i = 0; i < data.Length; i++)
            {
                data[i] = value++;
            }
            RSAKeys key = SecurityEx.RSAKeys(2048);


            RSAAlgorithmType algorithmType = RSAAlgorithmType.Default;
            byte[] encryptResult = SecurityEx.RSAEncrypt(data, key.PublicKey, algorithmType, RSAEncryptionPadding.OaepSHA1);
            byte[] decryptResult = SecurityEx.RSADecrypt(encryptResult, key.PrivateKey, algorithmType, RSAEncryptionPadding.OaepSHA1);

            //byte[] encryptResult = SecurityEx.RSAEncrypt(data, key.PublicKey);
            //byte[] decryptResult = SecurityEx.RSADecrypt(encryptResult, key.PrivateKey);

            if (data.Length != decryptResult.Length)
            {
                Console.WriteLine("RSR data.Length != decryptResult.Length fail.");
                return;
            }

            for (int j = 0; j < data.Length; j++)
            {
                if (data[j] != decryptResult[j])
                {
                    Console.WriteLine("RSR data[j] != decryptResult[j] fail.");
                    return;
                }
            }

            Console.WriteLine($"RSR ok.");
        }

        private static void TestSymmetric()
        {
            string filePath = @"D:\Temp\Program.cs";
            //byte[] data = File.ReadAllBytes(filePath);
            string text = File.ReadAllText(filePath);
            byte[] data = Encoding.UTF8.GetBytes(text);

            byte[] key = null, iv = null;

            SymmetricAlgorithmType[] arr = new SymmetricAlgorithmType[]
            {
                SymmetricAlgorithmType.Aes,
                SymmetricAlgorithmType.DES,
                SymmetricAlgorithmType.RC2,
                SymmetricAlgorithmType.TripleDES
            };


            foreach (var at in arr)
            {
                switch (at)
                {
                    case SymmetricAlgorithmType.Aes:
                        //key = Encoding.UTF8.GetBytes("qwertyuiasdfghjk");
                        //iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        key = new byte[16];
                        for (int i = 0; i < key.Length; i++)
                        {
                            key[i] = (byte)i;
                        }

                        iv = new byte[16];
                        for (int i = 0; i < iv.Length; i++)
                        {
                            iv[i] = (byte)i;
                        }
                        break;
                    case SymmetricAlgorithmType.DES:
                        key = Encoding.UTF8.GetBytes("abcdefgh");
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    case SymmetricAlgorithmType.RC2:
                        key = Encoding.UTF8.GetBytes("abcdefgh");
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    case SymmetricAlgorithmType.TripleDES:
                        key = Encoding.UTF8.GetBytes("ICryptoTransform");//至少16/24字节
                        iv = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xff };
                        break;
                    default:
                        break;
                }


                byte[] encryptResult = SecurityEx.SymmetricEncrypt(data, key, iv, at);
                byte[] decryptResult = SecurityEx.SymmetricDecrypt(encryptResult, key, iv, at);
                string text2 = Encoding.UTF8.GetString(decryptResult);
                if (string.Equals(text, text2))
                {
                    Console.WriteLine($"{at.ToString()}  ok.");
                }
                else
                {
                    Console.WriteLine($"{at.ToString()}  fail.");
                }

                byte[] encryptResult2 = SecurityEx.SymmetricEncryptText(text, key, iv, at);
                string text3 = SecurityEx.SymmetricDecryptText(encryptResult2, key, iv, at);
                if (string.Equals(text, text3))
                {
                    Console.WriteLine($"{at.ToString()} text ok.");
                }
                else
                {
                    Console.WriteLine($"{at.ToString()} text fail.");
                }
            }

        }

        private static void TestComputeHash()
        {
            string text = @"D:\Temp\Program.cs";
            byte[] data = File.ReadAllBytes(text);
            byte[] hash1 = SecurityEx.ComputeHash(data, HashAlgorithmType.SHA512);
            Console.WriteLine($"hash1:{ConvertEx.BytesToHexadecimaString(hash1, false, null)}");
        }

        private static void TestGetAlgorithmType()
        {
            Type targetType = typeof(RSA);
            Type[] types = targetType.Assembly.GetExportedTypes();
            var hashClass = types.Where(t => { return !t.IsAbstract && t.IsSubclassOf(targetType); }).ToArray();
            StringBuilder sb = new StringBuilder();
            foreach (var type in hashClass)
            {
                sb.AppendLine(type.Name);
            }
            string str = sb.ToString();

            var entry = SHA1.Create();
            /*
             * HashAlgorithm子类
             * HMACMD5
             * HMACRIPEMD160
             * HMACSHA1
             * HMACSHA256
             * HMACSHA384
             * HMACSHA512
             * MACTripleDES
             * MD5CryptoServiceProvider
             * RIPEMD160Managed
             * SHA1CryptoServiceProvider
             * SHA1Managed
             * SHA256Managed
             * SHA384Managed
             * SHA512Managed
             * 
             * 
             * 对称加密SymmetricAlgorithm子类
             * DESCryptoServiceProvider
             * RC2CryptoServiceProvider
             * RijndaelManaged
             * TripleDESCryptoServiceProvider
             * 
             * 非对称加密RSA子类
             * RSACryptoServiceProvider
             * */
        }








        #region demo

        //一、对称加密（AES/DES）
        //        - 密钥和IV需保持长度一致（AES支持128/192/256位密钥）。
        //- 实际应用中建议通过 Rfc2898DeriveBytes 生成密钥，避免硬编码。
        // 加密
        public static string Encrypt(string plainText, string key, string iv)
        {
            using (Aes aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(key);
                aes.IV = Encoding.UTF8.GetBytes(iv);

                using (MemoryStream ms = new MemoryStream())
                using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    byte[] data = Encoding.UTF8.GetBytes(plainText);
                    cs.Write(data, 0, data.Length);
                    cs.FlushFinalBlock();
                    return Convert.ToBase64String(ms.ToArray());
                }
            }
        }

        // 解密
        public static string Decrypt(string cipherText, string key, string iv)
        {
            using (Aes aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(key);
                aes.IV = Encoding.UTF8.GetBytes(iv);

                using (MemoryStream ms = new MemoryStream())
                using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    byte[] data = Convert.FromBase64String(cipherText);
                    cs.Write(data, 0, data.Length);
                    cs.FlushFinalBlock();
                    return Encoding.UTF8.GetString(ms.ToArray());
                }
            }
        }






        //        二、非对称加密（RSA）

        //非对称加密使用公钥加密、私钥解密（或反之），适合密钥交换和数字签名。
        //- RSA加密数据长度受密钥长度限制（2048位密钥最多加密214字节）。
        //- 实际应用中常配合对称加密使用（用RSA加密对称密钥）。

        // 生成密钥对
        public static Tuple<string, string> GenerateKeys()
        {
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048))
            {
                string publicKey = rsa.ToXmlString(false);
                string privateKey = rsa.ToXmlString(true);
                return new Tuple<string, string>(publicKey, privateKey);
            }
        }

        // 公钥加密
        public static string Encrypt(string plainText, string publicKey)
        {
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                rsa.FromXmlString(publicKey);
                byte[] data = Encoding.UTF8.GetBytes(plainText);
                byte[] encrypted = rsa.Encrypt(data, false);
                return Convert.ToBase64String(encrypted);
            }
            //RSAEncryptionPadding.Pkcs1
            //RSAEncryptionPadding.OaepSHA1
        }

        // 私钥解密
        public static string Decrypt(string cipherText, string privateKey)
        {
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                rsa.FromXmlString(privateKey);
                byte[] data = Convert.FromBase64String(cipherText);
                byte[] decrypted = rsa.Decrypt(data, false);
                return Encoding.UTF8.GetString(decrypted);
            }
        }





        //三、哈希算法（SHA/MD5）
        //哈希算法用于数据完整性校验（不可逆），常见于密码存储、文件校验。
        //        - 哈希算法不可逆，密码存储需配合盐值（Salt）防止彩虹表攻击。
        //- 生产环境建议使用SHA-256及以上算法（如SHA-512），避免使用MD5/SHA1。

        // SHA-256哈希
        public static string Sha256(string input)
        {
            using (SHA256 sha256 = SHA256.Create())
            {
                byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(input));
                return BitConverter.ToString(hash).Replace("-", "").ToLower();
            }
        }

        // MD5哈希（安全性较低，仅用于兼容旧系统）
        public static string Md5(string input)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
                return BitConverter.ToString(hash).Replace("-", "").ToLower();
            }
        }




        //        四、HMAC（哈希消息认证码）

        //结合密钥的哈希算法，用于验证数据完整性和身份认证。
        // 生成HMAC
        public static string GenerateHmac(string data, string key)
        {
            using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
            {
                byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
                return Convert.ToBase64String(hash);
            }
        }

        // 验证HMAC
        public static bool VerifyHmac(string data, string key, string hmac)
        {
            string generatedHmac = GenerateHmac(data, key);
            return string.Equals(generatedHmac, hmac);
        }

        /*
         
五、实际应用建议
 
1. 密钥管理：
- 避免硬编码密钥，使用配置文件或安全存储（如Windows DPAPI）。
- 对称加密的IV需随机生成，每次加密时随密文一起传输。
2. 安全性：
- 密码存储必须加盐（Salt），盐值需随机且与哈希值一同存储。
- 避免使用已过时的算法（如DES、MD5），优先使用AES+SHA256组合。
3. 性能优化：
- 大文件加密建议使用流操作（如 CryptoStream ），避免一次性加载内存。
 
通过以上类可实现常见加密需求，具体选择需根据业务场景（如数据量、安全性、性能）决定。

        */


        #endregion

    }
}
